package cn.schoolwow.sdk.baiduyun;

import cn.schoolwow.quickhttp.QuickHttp;
import cn.schoolwow.quickhttp.domain.RequestMeta;
import cn.schoolwow.quickhttp.listener.QuickHttpClientListener;
import cn.schoolwow.quickhttp.request.Request;
import cn.schoolwow.quickhttp.response.Response;
import cn.schoolwow.sdk.baiduyun.domain.*;
import cn.schoolwow.sdk.util.RegExpUtil;
import cn.schoolwow.sdk.weiyun.exception.WeiYunException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Stack;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 百度云SDK实现类
 */
public class BaiDuYunAPIImpl implements BaiDuYunAPI {
    private Logger logger = LoggerFactory.getLogger(BaiDuYunAPIImpl.class);
    private static int[] ns = new int[]{0, 2, 1};
    private static String u = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/~！@#￥%……&";
    private String logid;
    private String bdstoken;

    public BaiDuYunAPIImpl(String cookieString) {
        setCookie(cookieString);
    }

    @Override
    public void setCookie(String cookieString) {
        QuickHttp.clientConfig().cookieOption().addCookieString("baidu.com", cookieString);
        logid = w(QuickHttp.clientConfig().cookieOption().getCookie("baidu.com", "BAIDUID").getValue());
        try{
            String body = QuickHttp.connect("https://pan.baidu.com/disk/home").execute().body();
            bdstoken = RegExpUtil.plainMatch(body, "locals.set\\('bdstoken', '()'\\);");
            if (null == bdstoken) {
                bdstoken = RegExpUtil.plainMatch(body, "bdstoken\":\"()\"");
            }
            if (null == bdstoken) {
                throw new IOException("用户登录状态失效!");
            }
        }catch (IOException e){
            throw new RuntimeException(e);
        }

        QuickHttp.clientConfig().quickHttpClientListener(new QuickHttpClientListener() {
            @Override
            public void beforeExecute(Request request) throws IOException{
                RequestMeta requestMeta = request.requestMeta();
                if(requestMeta.url.getHost().contains("pan.baidu.com")){
                    request.ignoreHttpErrors(true);
                }
            }

            @Override
            public void executeSuccess(Request request, Response response) throws IOException{
                if(null==response.body()){
                    throw new IOException("获取返回结果内容为空!");
                }
                if (response.body().contains("页面不存在")) {
                    throw new BaiDuYunException(0, "页面不存在");
                }
                if(response.body().startsWith("{")||response.body().startsWith("[")){
                    JSONObject result = response.bodyAsJSONObject();
                    if (null!=result && result.containsKey("errno") && 0 != result.getInteger("errno")) {
                        if (result.containsKey("show_msg")) {
                            throw new IllegalArgumentException(result.getString("show_msg"));
                        }
                        throw new BaiDuYunException(result.getInteger("errno"), result.getString("err_msg"));
                    }
                    if (null!=result && result.containsKey("ret") && 0 != result.getInteger("ret")) {
                        throw new WeiYunException(result.getInteger("ret"), result.getString("msg"));
                    }
                }
            }

            @Override
            public void executeFail(Request request, Exception e) throws IOException{

            }
        });
    }

    @Override
    public BaiDuYunUser getBaiDuYunUser() throws IOException {
        String api = "https://pan.baidu.com/sbox/user/query";
        Response response = QuickHttp.connect(api).execute();
        JSONObject result = response.bodyAsJSONObject();
        BaiDuYunUser baiDuYunUser = result.toJavaObject(BaiDuYunUser.class);
        return baiDuYunUser;
    }

    @Override
    public BaiDuYunQuota quota() throws IOException {
        String api = "https://pan.baidu.com/api/quota?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&checkexpire=1&checkfree=1"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).execute();
        JSONObject result = response.bodyAsJSONObject();
        BaiDuYunQuota baiDuYunQuota = result.toJavaObject(BaiDuYunQuota.class);
        return baiDuYunQuota;
    }

    @Override
    public BaiDuYunShare verify(String url) throws IOException {
        String surl = "", key = "";
        //提取密码
        BaiDuYunShare baiDuYunShare = new BaiDuYunShare();
        int sharpIndex = url.lastIndexOf("#");
        if (sharpIndex > 0) {
            key = url.substring(sharpIndex + 1);
            if (url.contains("surl=")) {
                surl = RegExpUtil.plainMatch(url, "surl=()#");
                baiDuYunShare.surl = surl;
            } else {
                surl = RegExpUtil.plainMatch(url, "/s/()#");
                baiDuYunShare.surl = surl;
                //如果第一个是数字,则跳过
                if (Character.isDigit(surl.charAt(0))) {
                    surl = surl.substring(1);
                }
            }
        }
        if (!QuickHttp.clientConfig().cookieOption().hasCookie("baidu.com", "BAIDUID")) {
            QuickHttp.connect(url).execute();
        }
        if (!key.isEmpty()) {
            String api = "https://pan.baidu.com/share/verify?bdstoken=" + bdstoken + "&channel=chunlei&clienttype=0&web=1&app_id=250528&surl=" + surl + "&t=" + System.currentTimeMillis();
            Response response = QuickHttp.connect(api)
                    .method(Request.Method.POST)
                    .referrer("https://pan.baidu.com/share/init?surl=" + surl)
                    .data("vcode", "")
                    .data("vcode_str", "")
                    .data("pwd", key)
                    .ajax()
                    .execute();
            String setCookie = response.header("Set-Cookie").get(0);
            String BDCLND = RegExpUtil.plainMatch(setCookie, "BDCLND=();");
            baiDuYunShare.extra = "{\"sekey\":\"" + URLDecoder.decode(BDCLND + "\"}", "UTF-8");
        }
        Response response = QuickHttp.connect(url).execute();
        //链接过期
        if (response.url().contains("/error/404.html")) {
            throw new IOException("链接已过期");
        }

        JSONObject result = JSON.parseObject(getYunData(response.body()));
        baiDuYunShare.url = url;
        baiDuYunShare.shareId = result.getString("shareid");
        baiDuYunShare.uk = result.getString("share_uk");
        baiDuYunShare.sign = result.getString("sign");
        if (result.containsKey("timestamp")) {
            baiDuYunShare.timestamp = result.getLong("timestamp");
        }
        if (result.containsKey("ctime") && null != result.get("ctime")) {
            baiDuYunShare.ctime = new Timestamp(result.getLong("ctime") * 1000).toLocalDateTime();
        }
        baiDuYunShare.bdstoken = result.getString("bdstoken");
        baiDuYunShare.linkUserName = result.getString("linkusername");
        baiDuYunShare.sharesuk = result.getString("sharesuk");
        baiDuYunShare.photo = result.getString("photo");
        if (result.containsKey("public") && null != result.get("public")) {
            //判断分享类型是公共还是私密
            baiDuYunShare.publicShare = result.getInteger("public") == 1;
        } else if (result.containsKey("publicShare")) {
            baiDuYunShare.publicShare = result.getBoolean("publicShare");
        }
        if(!result.containsKey("file_list")){
            throw new IOException("百度云分享文件列表为空!");
        }
        Object fileList = result.get("file_list");
        JSONArray array = null;
        if (fileList instanceof JSONObject) {
            array = ((JSONObject) fileList).getJSONArray("list");
        } else if (fileList instanceof JSONArray) {
            array = (JSONArray) fileList;
        } else {
            logger.warn("[百度云分享文件列表参数(file_list)解析失败]file_list内容:{}",result.getString("file_list"));
            throw new IllegalArgumentException("百度云分享文件列表参数(file_list)解析失败!");
        }
        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);

            BaiDuYunFile baiDuYunFile = new BaiDuYunFile();
            getBaiDuYunFile(o, baiDuYunFile);
            baiDuYunFile.baiDuYunShare = baiDuYunShare;
            baiDuYunShare.baiDuYunFileList.add(baiDuYunFile);
        }
        return baiDuYunShare;
    }

    @Override
    public List<BaiDuYunFile> shareList(BaiDuYunShare baiDuYunShare, BaiDuYunFile baiDuYunFile) throws IOException{
        String api = "https://pan.baidu.com/share/list?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "order=other&desc=1&showempty=0&page=1&num=100";
        Response response = QuickHttp.connect(api)
                .parameter("dir",baiDuYunFile.path)
                .parameter("t",Math.random()+"")
                .parameter("bdstoken",bdstoken)
                .parameter("logid",logid)
                .parameter("shareid",baiDuYunShare.shareId)
                .parameter("uk",baiDuYunShare.uk)
                .execute();
        JSONArray array = response.bodyAsJSONObject().getJSONArray("list");
        List<BaiDuYunFile> baiDuYunFileList = new ArrayList<>(array.size());
        for(int i=0;i<array.size();i++){
            BaiDuYunFile subBaiDuYunFile = new BaiDuYunFile();
            getBaiDuYunFile(array.getJSONObject(i),subBaiDuYunFile);
            subBaiDuYunFile.baiDuYunShare = baiDuYunShare;
            baiDuYunFileList.add(subBaiDuYunFile);
        }
        return baiDuYunFileList;
    }

    @Override
    public void walkBaiDuYunShare(BaiDuYunShare baiDuYunShare, Consumer<BaiDuYunFile> baiDuYunFileConsumer) throws IOException {
        Stack<BaiDuYunFile> baiDuYunFileStack = new Stack<>();
        for(BaiDuYunFile baiDuYunFile:baiDuYunShare.baiDuYunFileList){
            baiDuYunFileStack.push(baiDuYunFile);
        }
        while(!baiDuYunFileStack.isEmpty()){
            BaiDuYunFile baiDuYunFile = baiDuYunFileStack.pop();
            if(!baiDuYunFile.isDir){
                baiDuYunFileConsumer.accept(baiDuYunFile);
            }else{
                List<BaiDuYunFile> baiDuYunFileList = shareList(baiDuYunShare,baiDuYunFile);
                for(BaiDuYunFile subBaiDuYunFile:baiDuYunFileList){
                    baiDuYunFileStack.push(subBaiDuYunFile);
                }
            }
        }
    }

    @Override
    public BaiDuYunShareDownload sharedownload(BaiDuYunFile baiDuYunFile) throws IOException {
        //获取sign和timestamp
        if (null == baiDuYunFile.baiDuYunShare.sign) {
            String api = "https://pan.baidu.com/share/tplconfig?fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0"
                    + "&surl=" + baiDuYunFile.baiDuYunShare.surl
                    + "&logid=" + logid;
            Response response = QuickHttp.connect(api).execute();
            JSONObject data = response.bodyAsJSONObject().getJSONObject("data");
            baiDuYunFile.baiDuYunShare.sign = data.getString("sign");
            baiDuYunFile.baiDuYunShare.timestamp = data.getLong("timestamp");
        }
        //获取下载链接
        String api = "https://pan.baidu.com/api/sharedownload?"
                + "channel=chunlei&clienttype=12&web=1&app_id=250528"
                + "&sign=" + baiDuYunFile.baiDuYunShare.sign
                + "&timestamp=" + baiDuYunFile.baiDuYunShare.timestamp;
        if (!baiDuYunFile.baiDuYunShare.publicShare && null == baiDuYunFile.baiDuYunShare.extra) {
            throw new IOException("extra参数获取失败!");
        }

        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .contentType(Request.ContentType.MULTIPART_FORMDATA)
                .data("extra", baiDuYunFile.baiDuYunShare.extra)
                .data("logid", logid)
                .data("fid_list", "[" + baiDuYunFile.fsId + "]")
                .data("primaryid", baiDuYunFile.baiDuYunShare.shareId)
                .data("uk", baiDuYunFile.baiDuYunShare.uk)
                .data("product", "share")
                .data("encrypt", "0")
                .userAgent("pan.baidu.com")
                .execute();
        JSONObject o = response.bodyAsJSONObject().getJSONArray("list").getJSONObject(0);
        BaiDuYunShareDownload baiDuYunDownload = new BaiDuYunShareDownload();
        getBaiDuYunFile(o, baiDuYunDownload);
        baiDuYunDownload.dlink = QuickHttp.connect(o.getString("dlink"))
                .userAgent("pan.baidu.com");
        baiDuYunDownload.context = o.getString("context");
        return baiDuYunDownload;
    }

    @Override
    public String transfer(BaiDuYunShare baiDuYunShare, String path) throws IOException {
        String api = "https://pan.baidu.com/share/transfer?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid
                + "&shareid=" + baiDuYunShare.shareId
                + "&from=" + baiDuYunShare.uk;
        StringBuilder fsidlist = new StringBuilder("[");
        for (BaiDuYunFile baiDuYunFile : baiDuYunShare.baiDuYunFileList) {
            fsidlist.append(baiDuYunFile.fsId + ",");
        }
        fsidlist.deleteCharAt(fsidlist.length() - 1);
        fsidlist.append("]");

        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("fsidlist", fsidlist.toString())
                .data("path", path)
                .ajax()
                .referrer(baiDuYunShare.url)
                .execute();
        return response.body();
    }

    @Override
    public String create(String path) throws IOException {
        String api = "https://pan.baidu.com/api/create?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid
                + "a=commit";
        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("path", path)
                .data("isdir", "1")
                .data("block_list", "[]")
                .ajax()
                .execute();
        return response.body();
    }

    @Override
    public BaiDuYunFile uploadFile(String remoteDirectoryPath, String filePath) throws IOException {
        //预创建文件
        String api = "https://pan.baidu.com/api/precreate?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Path localFilePath = Paths.get(filePath);
        String path = remoteDirectoryPath + (remoteDirectoryPath.endsWith("/")?"":"/") + localFilePath.getFileName();
        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("path", path)
                .data("autoinit", "1")
                .data("target_path", remoteDirectoryPath)
                .data("block_list","[\"5910a591dd8fc18c32a8f3df4fdc1761\"]")
                .data("local_mtime", (System.currentTimeMillis()/1000)+"")
                .ajax()
                .execute();
        String uploadId = response.bodyAsJSONObject().getString("uploadid");
        api = "https://c3.pcs.baidu.com/rest/2.0/pcs/superfile2?"
                + "method=upload&app_id=250528&channel=chunlei&clienttype=0&web=1"
                + "&logid=" + logid
                +"&path=" + URLEncoder.encode(path,"utf-8")
                +"&uploadid=" + uploadId
                +"&uploadsign=0&partseq=0";
        response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .contentType(Request.ContentType.MULTIPART_FORMDATA)
                .data("file",localFilePath)
                .execute();
        String md5 = response.bodyAsJSONObject().getString("md5");
        //实际创建文件
        api = "https://pan.baidu.com/api/create?"
                + "isdir=0&rtype=1&channel=chunlei&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid="+logid+"&clienttype=0";
        response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("path", path)
                .data("size", Files.size(localFilePath)+"")
                .data("uploadid", uploadId)
                .data("target_path", URLEncoder.encode(remoteDirectoryPath,"utf-8"))
                .data("block_list","[\""+md5+"\"]")
                .data("local_mtime", (System.currentTimeMillis()/1000)+"")
                .execute();
        BaiDuYunFile baiDuYunFile = response.bodyAsJSONObject().toJavaObject(BaiDuYunFile.class);
        return baiDuYunFile;
    }

    @Override
    public List<BaiDuYunFile> list(String dir) throws IOException {
        String api = "https://pan.baidu.com/api/list";
        Response response = QuickHttp.connect(api)
                .parameter("dir", dir)
                .parameter("page", "1")
                .parameter("num", "100")
                .parameter("order", "time")
                .parameter("desc", "1")
                .parameter("showempty", "0")
                .parameter("clienttype", "0")
                .parameter("web", "1")
                .parameter("app_id", "250528")
                .parameter("channel", "chunlei")
                .parameter("logid", logid)
                .ajax()
                .execute();
        JSONArray array = response.bodyAsJSONObject().getJSONArray("list");
        List<BaiDuYunFile> baiDuYunFileList = new ArrayList<>(array.size());
        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);

            BaiDuYunFile baiDuYunFile = new BaiDuYunFile();
            getBaiDuYunFile(o, baiDuYunFile);
            baiDuYunFileList.add(baiDuYunFile);
        }
        return baiDuYunFileList;
    }

    @Override
    public List<BaiDuYunFile> search(String key) throws IOException {
        String api = "https://pan.baidu.com/api/search?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&page=1&num=100&showempty=0&desc=1"
                + "&key=" + key
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).ajax().execute();
        JSONArray array = response.bodyAsJSONObject().getJSONArray("list");
        List<BaiDuYunFile> baiDuYunFileList = new ArrayList<>();

        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);

            BaiDuYunFile baiDuYunFile = new BaiDuYunFile();
            getBaiDuYunFile(o, baiDuYunFile);
            baiDuYunFileList.add(baiDuYunFile);
        }
        return baiDuYunFileList;
    }

    @Override
    public String download(BaiDuYunFile baiDuYunFile) throws IOException {
        String api = "https://pan.baidu.com/api/download?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&type=dlink&vip=2"
                //TODO 百度网盘改变,以下参数暂时不知道如何获取
//                +"&sign="+yunData.getString("sign")
//                +"&timestamp="+yunData.getString("timestamp")
                + "&fidlist=[" + baiDuYunFile.fsId + "]"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).ajax().execute();
        return response.bodyAsJSONObject().getJSONArray("dlink").getJSONObject(0).getString("dlink");
    }

    @Override
    public Request pcsDownload(BaiDuYunFile baiDuYunFile) throws IOException {
        String api = "https://pan.baidu.com/rest/2.0/xpan/multimedia?"
                + "method=filemetas&dlink=1"
                + "&fsids=[" + baiDuYunFile.fsId + "]";
        JSONObject result = QuickHttp.connect(api).execute().bodyAsJSONObject();
        return QuickHttp.connect(result.getJSONArray("list").getJSONObject(0).getString("dlink"));
    }

    @Override
    public Request clientDownload(BaiDuYunFile baiDuYunFile) throws IOException {
        BaiDuYunShareDownload baiDuYunShareDownload = sharedownload(baiDuYunFile);
        return baiDuYunShareDownload.dlink.userAgent("netdisk;7.0.4.11;PC;PC-Windows;10.0.18362;WindowsBaiduYunGuanJia");
    }

    @Override
    public List<BaiDuYunShareLink> record() throws IOException {
        String api = "https://pan.baidu.com/share/record?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).ajax().execute();
        JSONArray array = response.bodyAsJSONObject().getJSONArray("list");
        List<BaiDuYunShareLink> baiDuYunShareLinkList = new ArrayList<>();
        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);

            BaiDuYunShareLink baiDuYunShareLink = new BaiDuYunShareLink();
            getBaiDuYunShareLink(o, baiDuYunShareLink);
            baiDuYunShareLinkList.add(baiDuYunShareLink);
        }
        return baiDuYunShareLinkList;
    }

    @Override
    public BaiDuYunShareLink share(BaiDuYunFile baiDuYunFile, int period, String pwd) throws IOException {
        String api = "https://pan.baidu.com/share/set?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("schannel", "4")
                .data("channel_list", "[]")
                .data("period", period + "")
                .data("pwd", pwd)
                .data("fid_list", "[" + baiDuYunFile.fsId + "]")
                .ajax()
                .execute();
        JSONObject result = response.bodyAsJSONObject();
        BaiDuYunShareLink baiDuYunShareLink = new BaiDuYunShareLink();
        baiDuYunShareLink.fsId = baiDuYunFile.fsId;
        getBaiDuYunShareLink(result, baiDuYunShareLink);
        return baiDuYunShareLink;
    }

    @Override
    public BaiDuYunShareLink pshare(BaiDuYunFile baiDuYunFile, int period) throws IOException {
        String api = "https://pan.baidu.com/share/pset?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("schannel", "0")
                .data("channel_list", "[]")
                .data("period", period + "")
                .data("path_list", "[\"" + baiDuYunFile.path + "\"]")
                .ajax()
                .execute();
        JSONObject o = response.bodyAsJSONObject();
        BaiDuYunShareLink baiDuYunShareLink = new BaiDuYunShareLink();
        baiDuYunShareLink.fsId = baiDuYunFile.fsId;
        getBaiDuYunShareLink(o, baiDuYunShareLink);
        return baiDuYunShareLink;
    }

    @Override
    public void cancel(BaiDuYunShareLink... baiDuYunShareLinks) throws IOException {
        String api = "https://pan.baidu.com/share/record?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        StringBuilder shareIdBuilder = new StringBuilder();
        for (BaiDuYunShareLink baiDuYunShareLink : baiDuYunShareLinks) {
            shareIdBuilder.append(baiDuYunShareLink.fsId + ",");
        }
        shareIdBuilder.deleteCharAt(shareIdBuilder.length() - 1);
        QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("shareid_list", "[" + shareIdBuilder.toString() + "]")
                .ajax()
                .execute();
    }

    @Override
    public void renameFile(BaiDuYunFile baiDuYunFile, String newName) throws IOException {
        String api = "https://pan.baidu.com/api/filemanager?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&opera=rename&async=2&onnest=fail"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("filelist", "[{\"path\":\"" + baiDuYunFile.path + "\",\"newname\":\"" + newName + "\"}]")
                .ajax()
                .execute();
    }

    @Override
    public void delete(BaiDuYunFile... baiDuYunFiles) throws IOException {
        String api = "https://pan.baidu.com/api/filemanager?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&opera=delete&async=2&onnest=fail"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;

        StringBuilder builder = new StringBuilder();
        for (BaiDuYunFile baiDuYunFile : baiDuYunFiles) {
            builder.append("\"" + baiDuYunFile.path + "\",");
        }
        builder.deleteCharAt(builder.length() - 1);
        QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("filelist", "[" + builder.toString() + "]")
                .ajax()
                .execute();
    }

    @Override
    public List<BaiDuYunFile> recycleList() throws IOException {
        String api = "https://pan.baidu.com/api/recycle/list?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&page=1&num=100"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).ajax().execute();
        JSONArray array = response.bodyAsJSONObject().getJSONArray("list");
        List<BaiDuYunFile> baiDuYunFileList = new ArrayList<>();
        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);

            BaiDuYunFile baiDuYunFile = new BaiDuYunFile();
            getBaiDuYunFile(o, baiDuYunFile);
            baiDuYunFileList.add(baiDuYunFile);
        }
        return baiDuYunFileList;
    }

    @Override
    public void restore(BaiDuYunFile... baiDuYunFiles) throws IOException {
        String api = "https://pan.baidu.com/api/recycle/restore?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&async=1"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        StringBuilder builder = new StringBuilder();
        for (BaiDuYunFile baiDuYunFile : baiDuYunFiles) {
            builder.append("" + baiDuYunFile.fsId + ",");
        }
        builder.deleteCharAt(builder.length() - 1);
        QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("fidlist", "[" + builder.toString() + "]")
                .ajax().execute();
    }

    @Override
    public void recycleDelete(BaiDuYunFile... baiDuYunFiles) throws IOException {
        String api = "https://pan.baidu.com/api/recycle/delete?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&async=1"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        StringBuilder builder = new StringBuilder();
        for (BaiDuYunFile baiDuYunFile : baiDuYunFiles) {
            builder.append("" + baiDuYunFile.fsId + ",");
        }
        builder.deleteCharAt(builder.length() - 1);
        QuickHttp.connect(api)
                .method(Request.Method.POST)
                .data("fidlist", "[" + builder.toString() + "]")
                .ajax().execute();
    }

    @Override
    public void clear() throws IOException {
        String api = "https://pan.baidu.com/api/recycle/clear?"
                + "channel=chunlei&clienttype=0&web=1&app_id=250528&async=1"
                + "&bdstoken=" + bdstoken
                + "&logid=" + logid;
        Response response = QuickHttp.connect(api).ajax().execute();
    }

    private String getYunData(String body) throws IOException {
        String yunData = RegExpUtil.plainMatch(body, "yunData.setData\\(()}\\);");
        if (null == yunData) {
            yunData = RegExpUtil.plainMatch(body, "window.yunData = ()};");
        }
        if (null == yunData) {
            yunData = RegExpUtil.plainMatch(body, "locals.mset\\(()}\\);");
        }
        if (null == yunData) {
            throw new IOException("yunData提取失败!");
        }
        yunData = yunData + "}";
        return yunData;
    }

    private void getBaiDuYunShareLink(JSONObject o, BaiDuYunShareLink baiDuYunShareLink) {
        baiDuYunShareLink.ctime = o.getDate("ctime");
        if (o.containsKey("expiredType")) {
            baiDuYunShareLink.expiredType = o.getInteger("expiredType");
        }
        if (o.containsKey("fsIds")) {
            baiDuYunShareLink.fsId = o.getJSONArray("fsIds").getString(0);
        }
        if (o.containsKey("shareid")) {
            baiDuYunShareLink.shareid = o.getString("shareid");
        } else {
            baiDuYunShareLink.shareid = o.getString("shareId");
        }
        if (o.containsKey("link")) {
            baiDuYunShareLink.link = o.getString("link");
        } else {
            baiDuYunShareLink.link = o.getString("shortlink");
        }
        baiDuYunShareLink.shorturl = o.getString("shorturl");
    }

    /**
     * 获取百度云文件信息
     * */
    private void getBaiDuYunFile(JSONObject o, BaiDuYunFile baiDuYunFile) {
        baiDuYunFile.category = o.getString("category");
        baiDuYunFile.fsId = o.getString("fs_id");
        baiDuYunFile.isDir = o.getBoolean("isdir");
        if (o.containsKey("local_ctime") && null != o.get("local_ctime")) {
            baiDuYunFile.localCTime = new Timestamp(o.getLong("local_ctime") * 1000).toLocalDateTime();
        }
        baiDuYunFile.md5 = o.getString("md5");
        baiDuYunFile.path = o.getString("path");
        if (o.containsKey("server_ctime") && null != o.get("server_ctime")) {
            baiDuYunFile.serverCTime = new Timestamp(o.getLong("server_ctime") * 1000).toLocalDateTime();
        }
        baiDuYunFile.serverFileName = o.getString("server_filename");
        baiDuYunFile.size = o.getInteger("size");
    }

    private static String s(String j, String r) {
        int[] a = new int[256];
        int[] p = new int[256];
        byte[] o = new byte[r.length()];
        int v = j.length();
        for (int q = 0; q < 256; q++) {
            a[q] = Character.codePointAt(j.charAt(q % v) + "", 0);
            p[q] = q;
        }
        for (int u = 0, q = 0; q < 256; q++) {
            u = (u + p[q] + a[q]) % 256;
            int t = p[q];
            p[q] = p[u];
            p[u] = t;
        }
        for (int i = 0, u = 0, q = 0; q < r.length(); q++) {
            i = (i + 1) % 256;
            u = (u + p[i]) % 256;
            int t = p[i];
            p[i] = p[u];
            p[u] = t;
            int k = p[((p[i] + p[u]) % 256)];
            o[q] = (byte) (Character.codePointAt(r, q) ^ k);
        }
        return Base64.getEncoder().encodeToString(o);
    }

    private static String g(String e) {
        return (e + "" + Math.random());
    }

    private static String m(String e) {
        int n = ns[e.length() % 3];
        int t = e.charAt(0) << 16 | (e.length() > 1 ? e.charAt(1) : 0) << 8 | (e.length() > 2 ? e.charAt(2) : 0);
        char[] chs = new char[]{
                (u.charAt(t >>> 18)),
                (u.charAt(t >>> 12 & 63)),
                (n >= 2 ? '=' : (char) u.charAt(t >>> 6 & 63)),
                (n >= 1 ? '=' : u.charAt(63 & t))
        };
        String o = String.valueOf(chs);
        return o;
    }

    private static String h(String e) {
        String ee = "";
        Matcher m = Pattern.compile("[\\s\\S]{1,3}").matcher(e);
        while (m.find()) {
            ee += m(m.group());
        }
        return ee;
    }

    private static String p() {
        return h(g(System.currentTimeMillis() + ""));
    }

    private static String w(String e) {
        return p();
    }

}
